﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Reflection;

namespace EntityMap.Meta
{
    /// <summary>
    /// This class is used for sql statement that return one entity.
    /// </summary>
    public class SingleSelectStatement : SelectStatement
    {
        public override object Process<T>( Context ctx )
        {
            T obj = Activator.CreateInstance<T>();

            Type entityType = typeof( T );

            using( SqlConnection conn = new SqlConnection( ctx.Mapper.ConnectionString ) )
            {
                SqlCommand cmd =  new SqlCommand( this.Command, conn );

                if( ctx.ParameterMap != null )
                {
                    cmd.Parameters.AddRange( ctx.ParameterMap.GetSqlParameters( ctx.Parameter ) );
                }

                conn.Open();

                SqlDataReader reader = cmd.ExecuteReader();

                // create and fill new object
                if( reader.Read() )
                {
                    foreach( Field fi in ctx.ResultMap.Fields )
                    {
                        PropertyInfo pinfo = entityType.GetProperty( fi.Property );

                        object result;

                        // check for join
                        if( fi is ComplexField )
                        {
                            MethodInfo minfo = typeof( EntityMapper ).GetMethod( "ExecuteStatement" );
                            MethodInfo gminfo = minfo.MakeGenericMethod( pinfo.PropertyType );

                            result = gminfo.Invoke( ctx.Mapper,
                                                    new object[] {( (ComplexField)fi ).SelectStatement,
                                                    ctx.Parameter } );
                        }
                        else
                        {
                            result = reader[fi.Column];
                        }
                        pinfo.SetValue( obj, result, null );
                    }
                }
            }
            return obj;
        }
    }
}
